#include "row_text.h"

#include <limits>

#include <QString>
#include <QStringList>

#include "bit_range.h"
#include "row_text_templates.h"


namespace BitWin
{


// Anonymous namespace for internal usage staff
namespace
{


//---- RowText concreete classes


// Empty RowText data source.

class NullData: public RowText
{
public:
    virtual int size() const;
    virtual QString at(int) const;
};

int NullData::size() const
{
    return 0;
}

QString NullData::at(int) const
{
    return QString();
}


// RAMP RowText data
class RampData: public RowText
{
public:
    virtual int size() const;
    virtual QString at(int index) const;
};

int RampData::size() const
{
    return std::numeric_limits<int>::max();
}

QString RampData::at(int index) const
{
    return QString::number(index);
}


//---- RowText decorator classes


// Abstract range-based decorator class

class RangeDecorator: public RowText
{
    const PRowText _decorated;
    const BitRange _range;

protected:
    const BitRange& range() const
        {return _range;}
    const PRowText& decorated() const
        {return _decorated;}

    RangeDecorator(const RowText* decorated_, const BitRange& range_);
};

RangeDecorator::RangeDecorator(
    const RowText* decorated_, const BitRange& range_
):
    _decorated(decorated_),
    _range(range_)
{}


// Concreete decorator classes


// Decorator providing RowText::mid method

class MidDecorator: public RangeDecorator
{
public:

    MidDecorator(const RowText* decorated_, const BitRange& range_);

    virtual int size() const;
    virtual QString at(int index) const;
};

MidDecorator::MidDecorator(
    const RowText* decorated_, const BitRange& range_
):
    RangeDecorator(decorated_, range_)
{}

int MidDecorator::size() const
{
    return range().length();
}

QString MidDecorator::at(int index) const
{
    if (
        (index >= 0) &&
        (static_cast<unsigned>(index) < range().length())
    )
        return decorated()->at(index + range().begin());
    else
        return QString();
}


// Decorator providing RowText::viewIn method

class ViewInDecorator: public RangeDecorator
{
public:

    ViewInDecorator(const RowText* decorated_, const BitRange& range_);

    virtual int size() const;
    virtual QString at(int index) const;
};

ViewInDecorator::ViewInDecorator(
    const RowText* decorated_, const BitRange& range_
):
    RangeDecorator(decorated_, range_)
{}

int ViewInDecorator::size() const
{
    return decorated()->size();
}

QString ViewInDecorator::at(int index) const
{
    if (
        (index >= 0) &&
        // HACK! There should be bool BitRange::isInclude(int i) const
        // method!
        (static_cast<unsigned>(index) >= range().begin()) &&
        (static_cast<unsigned>(index) < range().end())
    )
        return decorated()->at(index);
    else
        return QString();
}


} // Anonymous namespace end


//---- RowText itself

RowText::RowText() {}
RowText::~RowText() {}

PRowText RowText::mid(const BitRange& range) const
{
    return PRowText(new MidDecorator(this, range));
}

PRowText RowText::viewIn(const BitRange& range) const
{
    return PRowText(new ViewInDecorator(this, range));
}


//---- PRowText itself

PRowText::PRowText():
    _pointee(new NullData())
{}

PRowText::PRowText(const RowText* p):
    _pointee(p)
{}

const RowText* const PRowText::operator->() const
{
    return _pointee.data();
}

bool PRowText::operator==(const BitWin::PRowText& rhs) const
{
    if ((*this)->size() != rhs->size())
        return false;
    
    for (int i = 0; i < (*this)->size(); ++i)
    {
        QString s1((*this)->at(i)), s2(rhs->at(i));
        if (!
            (
                (s1 == s2) ||
                // HACK! We don't distinguish spaces-only,
                // null and empty strings.
                (
                    s1.trimmed().isEmpty() &&
                    s2.trimmed().isEmpty()
                )
            )
        )
            return false;
    }
    
    return true;
}


PRowText PRowText::RAMP(new RampData());


} // BitWin namespace end
